package main

import (
	"fmt"
	"sort"
	"strconv"
)

// We are working on a security system for a badged-access room in our company"s building.

// We want to find employees who badged into our secured room unusually often. We have an unordered list of names and entry times over a single day. Access times are given as numbers up to four digits in length using 24-hour time, such as "800" or "2250".

// Write a function that finds anyone who badged into the room three or more times in a one-hour period. Your function should return each of the employees who fit that criteria, plus the times that they badged in during the one-hour period. If there are multiple one-hour periods where this was true for an employee, just return the first one.

// badge_times = [
// ["Paul", "1355"],
// ["Jennifer", "1910"],
// ["John", "835"],
// ["John", "830"],
// ["Paul", "1315"],
// ["John", "1615"],
// ["John", "1640"],
// ["Paul", "1405"],
// ["John", "855"],
// ["John", "930"],
// ["John", "915"],
// ["John", "730"],
// ["John", "940"],
// ["Jennifer", "1335"],
// ["Jennifer", "730"],
// ["John", "1630"],
// ["Jennifer", "5"]
// ]

// Expected output (in any order)
// John: 830 835 855 915 930
// Paul: 1315 1355 1405

func invalidAccesses(records [][2]string) map[string][]int {
	res := make(map[string][]int)
	access := make(map[string][]int)

	for _, record := range records {
		name := record[0]
		time, _ := strconv.Atoi(record[1])
		if _, ok := access[name]; ok == false {
			access[name] = []int{time}
		} else {
			access[name] = append(access[name], time)
		}
	}

	for name, accesses := range access {
		sort.Ints(accesses)

		oneHourWindow := []int{}
		for i := 0; i < len(accesses); i++ {
			start := accesses[i]
			j := i + 1
			oneHourWindow = append(oneHourWindow, start)
			for j < len(accesses) && accesses[j]-start <= 100 {
				// within one hour
				oneHourWindow = append(oneHourWindow, accesses[j])
				j++
			}
			if len(oneHourWindow) >= 3 {
				if _, ok := res[name]; ok == false {
					res[name] = oneHourWindow
				}
			}
			oneHourWindow = []int{}
		}

	}

	// fmt.Println(res)
	return res
}

// We want to find employees who badged into our secured room together often. Given an unordered list of names and access times over a single day, find the largest group of people that were in the room together during two or more separate time periods, and the times when they were all present.
// badge_records = [
// ["Paul", "1214", "enter"],
// ["Paul", "830", "enter"],
// ["Curtis", "1100", "enter"],
// ["Paul", "903", "exit"],
// ["John", "908", "exit"],
// ["Paul", "1235", "exit"],
// ["Jennifer", "900", "exit"],
// ["Curtis", "1330", "exit"],
// ["John", "815", "enter"],
// ["Jennifer", "1217", "enter"],
// ["Curtis", "745", "enter"],
// ["John", "1230", "enter"],
// ["Jennifer", "800", "enter"],
// ["John", "1235", "exit"],
// ["Curtis", "810", "exit"],
// ["Jennifer", "1240", "exit"],
// ]

// Expected output:
// John, Paul, Jennifer: 830 to 900, 1230 to 1235

// For this input data:
// From 830 til 900, the room contains Jennifer, John, and Paul.
// From 1230 til 1235, the room contains Curtis, Paul, Jennifer, and John.

// The group "Jennifer, John, Paul" exists at both of these times, and is the largest group that exists multiple times.

// You should note that the group is a subset of the people in the room from 1230 to 1235

type Action struct {
	time   int
	action string
	name   string
}

func invalidGrouping(history [][3]string) {

	records := []Action{}

	names := make(map[string]bool)
	times := make(map[int]bool)

	for _, record := range history {

		names[record[0]] = true
		time, _ := strconv.Atoi(record[1])
		times[time] = true
		records = append(records, Action{
			time:   time,
			action: record[2],
			name:   record[0],
		})
	}
	sort.Slice(records, func(i, j int) bool {
		return records[i].time <= records[j].time
	})
	fmt.Println(records)
	fmt.Println(names)
}
func main() {
	input1 := [][2]string{
		[2]string{"Paul", "1355"},
		[2]string{"Jennifer", "1910"},
		[2]string{"John", "835"},
		[2]string{"John", "830"},
		[2]string{"Paul", "1315"},
		[2]string{"John", "1615"},
		[2]string{"John", "1640"},
		[2]string{"Paul", "1405"},
		[2]string{"John", "855"},
		[2]string{"John", "930"},
		[2]string{"John", "915"},
		[2]string{"John", "730"},
		[2]string{"John", "940"},
		[2]string{"Jennifer", "1335"},
		[2]string{"Jennifer", "730"},
		[2]string{"John", "1630"},
		[2]string{"Jennifer", "5"},
	}

	input1_1 := [][2]string{
		[2]string{"James", "1300"},
		[2]string{"Martha", "1600"},
		[2]string{"Martha", "1620"},
		[2]string{"Martha", "1530"},
	}
	// input2 := [][3]string{
	// 	[3]string{"Paul", "1214", "enter"},
	// 	[3]string{"Paul", "830", "enter"},
	// 	[3]string{"Curtis", "1100", "enter"},
	// 	[3]string{"Paul", "903", "exit"},
	// 	[3]string{"John", "908", "exit"},
	// 	[3]string{"Paul", "1235", "exit"},
	// 	[3]string{"Jennifer", "900", "exit"},
	// 	[3]string{"Curtis", "1330", "exit"},
	// 	[3]string{"John", "815", "enter"},
	// 	[3]string{"Jennifer", "1217", "enter"},
	// 	[3]string{"Curtis", "745", "enter"},
	// 	[3]string{"John", "1230", "enter"},
	// 	[3]string{"Jennifer", "800", "enter"},
	// 	[3]string{"John", "1235", "exit"},
	// 	[3]string{"Curtis", "810", "exit"},
	// 	[3]string{"Jennifer", "1240", "exit"},
	// }
	fmt.Println(invalidAccesses(input1))
	fmt.Println(invalidAccesses(input1_1))

	// invalidGrouping(input2)
}
